﻿using System;
using System.Collections.Generic;
using System.Text;
using Graffiti.Core;
using System.Collections.Specialized;
using System.Web;
using System.Net;
using System.Configuration;
using DataBuddy;

namespace GraffitiExtras.Plugins.Waegis
{
    public class WaegisChecker : GraffitiEvent
    {
        #region Fields

        public string APIKEY;
        public string RANKTOADD;
        public string DOMAINNAME;
        private string _applicationName = "Telligent Graffiti CMS";

        #endregion

        #region EditableForm Members

        public override string Name
        {
            get
            {
                return "Waegis Spam Filter";
            }
        }

        public override string Description
        {
            get
            {
                return
                    "Plug-in to check comments and trackbacks with <a href='http://waegis.com'>Waegis</a> API. " +
                    "Done by <a href='http://nayyeri.net'>Keyvan Nayyeri</a>";
            }
        }

        public override bool IsEditable
        {
            get
            {
                return true;
            }
        }

        protected override NameValueCollection DataAsNameValueCollection()
        {
            NameValueCollection nvc = base.DataAsNameValueCollection();
            nvc["APIKEY"] = APIKEY;
            nvc["RANKTOADD"] = RANKTOADD;
            nvc["DOMAINNAME"] = DOMAINNAME;

            return nvc;
        }

        public override StatusType SetValues(HttpContext context, NameValueCollection nvc)
        {
            base.SetValues(context, nvc);
            APIKEY = nvc["APIKEY"];
            RANKTOADD = nvc["RANKTOADD"];
            DOMAINNAME = nvc["DOMAINNAME"];
            return StatusType.Success;
        }

        protected override FormElementCollection AddFormElements()
        {
            FormElementCollection fec = new FormElementCollection();

            fec.Add(new TextFormElement("APIKEY", "API Key", "Your private unique API key"));
            fec.Add(new TextFormElement("RANKTOADD", "Rank", "Integer rank to add for spam items"));
            fec.Add(new TextFormElement("DOMAINNAME", "Domain Name", "Your domain name that will be used for site instance without http:// prefix (i.e. nayyeri.net)"));

            return fec;
        }

        #endregion

        #region GraffitiEvent Members

        public override void Init(GraffitiApplication ga)
        {
            ga.BeforeInsert += new DataObjectEventHandler(ga_BeforeInsert);
            ga.BeforeUpdate += new DataObjectEventHandler(ga_BeforeUpdate);
            ga.BeforeRemove += new DataObjectEventHandler(ga_BeforeRemove);
        }

        void ga_BeforeInsert(DataBuddyBase dataObject, EventArgs e)
        {
            Comment comment = dataObject as Comment;

            if (comment != null)
            {
                try
                {
                    string siteInstance = GetSiteInstance();

                    WaegisClient.WaegisClient client = new WaegisClient.WaegisClient(APIKEY, new Uri(siteInstance),
                        this._applicationName, SiteSettings.Version);

                    if (client.InitializeSiteInstance())
                    {
                        WaegisClient.Components.Post post = GetWaegisPost(comment, siteInstance);

                        int threshold = int.Parse(ConfigurationManager.AppSettings["Graffiti:Spam:Score"]);

                        if (comment.SpamScore >= threshold)
                        {
                            client.ReportSpam(post);
                            Log.Info("Waegis Spam Filter", "A post was originally spam and reported as spam");
                        }

                        if (client.CheckPost(post))
                        {
                            comment.SpamScore += int.Parse(RANKTOADD);

                            if (comment.SpamScore >= threshold)
                            {
                                comment.IsPublished = false;
                                Log.Info("Waegis Spam Filter", "A post is marked as spam");
                            }
                        }
                    }
                    else
                    {
                        Log.Error("Waegis Spam Filter", "Site instance is invalid");
                    }
                }
                catch (Exception ex)
                {
                    Log.Error("Waegis Spam Filter", ex.Message + ex.StackTrace);
                }
            }
        }

        void ga_BeforeUpdate(DataBuddyBase dataObject, EventArgs e)
        {
            Comment comment = dataObject as Comment;

            if (comment != null)
            {
                try
                {
                    string siteInstance = GetSiteInstance();

                    WaegisClient.WaegisClient client = new WaegisClient.WaegisClient(APIKEY, new Uri(siteInstance),
                        this._applicationName, SiteSettings.Version);

                    if (client.InitializeSiteInstance())
                    {
                        WaegisClient.Components.Post post = GetWaegisPost(comment, siteInstance);

                        Column Id = Comment.Columns.Id;
                        Comment originalComment = CommentCollection.FetchByColumn(Id, comment.Id)[0];
                        if ((!originalComment.IsPublished) && (comment.IsPublished))
                        {
                            if (client.ReportHam(post))
                                Log.Info("Waegis Spam Filter", "A post is reported as ham");
                        }
                    }
                    else
                    {
                        Log.Error("Waegis Spam Filter", "Site instance is invalid");
                    }
                }
                catch (Exception ex)
                {
                    Log.Error("Waegis Spam Filter", ex.Message + ex.StackTrace);
                }
            }
        }

        void ga_BeforeRemove(DataBuddyBase dataObject, EventArgs e)
        {
            Comment comment = dataObject as Comment;

            if (comment != null)
            {
                try
                {
                    string siteInstance = GetSiteInstance();

                    WaegisClient.WaegisClient client = new WaegisClient.WaegisClient(APIKEY, new Uri(siteInstance),
                        this._applicationName, SiteSettings.Version);

                    if (client.InitializeSiteInstance())
                    {
                        WaegisClient.Components.Post post = GetWaegisPost(comment, siteInstance);

                        Column Id = Comment.Columns.Id;
                        Comment originalComment = CommentCollection.FetchByColumn(Id, comment.Id)[0];
                        if ((!originalComment.IsDeleted) && (comment.IsDeleted))
                        {
                            if (client.ReportSpam(post))
                                Log.Info("Waegis Spam Filter", "A post is reported as spam");
                        }
                    }
                    else
                    {
                        Log.Error("Waegis Spam Filter", "Site instance is invalid");
                    }
                }
                catch (Exception ex)
                {
                    Log.Error("Waegis Spam Filter", ex.Message + ex.StackTrace);
                }
            }
        }

        #endregion

        #region Private Methods

        private string GetSiteInstance()
        {
            if (DOMAINNAME.ToLower().StartsWith("http://"))
                return DOMAINNAME.ToLower();
            else
                return string.Format("http://{0}", DOMAINNAME);
        }

        private GraffitiExtras.Plugins.Waegis.WaegisClient.Components.Post GetWaegisPost(Comment comment, string siteInstance)
        {
            GraffitiExtras.Plugins.Waegis.WaegisClient.Components.Post post = new GraffitiExtras.Plugins.Waegis.WaegisClient.Components.Post();

            HttpContext context = HttpContext.Current;

            if (!string.IsNullOrEmpty(comment.Name))
                post.AuthorName = comment.Name;
            if ((!string.IsNullOrEmpty(comment.WebSite)) && (comment.WebSite != "http://"))
                post.AuthorUrl = new Uri(comment.WebSite);
            if (!string.IsNullOrEmpty(comment.Email))
                post.AuthorEmail = comment.Email;
            if (!string.IsNullOrEmpty(comment.Title))
                post.Title = comment.Title;

            post.Body = comment.Body;
            post.Permalink = new Uri(new Macros().FullUrl(comment.Post.Url));
            post.PostType = (comment.IsTrackback ? WaegisClient.Components.PostType.Trackback : WaegisClient.Components.PostType.Comment);
            if (context.Request.UrlReferrer != null)
                post.Referrer = context.Request.UrlReferrer;

            post.UserAgent = context.Request.UserAgent;
            post.UserIP = IPAddress.Parse(GetUserHostAddress());

            return post;
        }

        private string GetUserHostAddress()
        {
            HttpContext context = HttpContext.Current;
            string result = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
            if (string.IsNullOrEmpty(result))
                return context.Request.UserHostAddress;

            int pos = result.IndexOf(",", StringComparison.InvariantCulture);
            if (pos > 0)
                return result.Substring(0, pos);
            else
                return result;
        }

        #endregion
    }
}
